home *** CD-ROM | disk | FTP | other *** search
- //
- // CopyBits Demo.c
- //
- // Written in May 1995 using Metrowerks CodeWarrior v5.
- //
- // The CopyBits Demo project v1.5 by Kenneth Worley.
- // This code is Copyright 1995. All Rights Reserved.
- // You may use this code in any project of your own. You may also
- // redistribute this project to anyone else as long as 1) all the
- // project files (including documentation files) are kept together,
- // and 2) nothing is charged for the project.
- //
- // Please ask my permission before including this code on any
- // disk or CD for sale.
- //
- // This is a tutorial project that demonstrates the use of
- // CopyBits and offscreen Graphics Worlds (GWorlds). It shows
- // several instances of copying images to and from offscreen
- // graphics worlds using CopyBits, provides several macros that
- // make the process a little easier, shows an example of
- // drawing into an offscreen graphics world and how that can
- // improve onscreen animation, and it demonstrates a "fade"
- // using CopyBits to fade a portion of the screen to black.
- //
- // Version 1.5 adds a fade from image to image using CopyBits.
- // Cool!
- //
- // In a nutshell, the app puts up a dialog that shows two
- // "source" pictures (1 & 2) and a destination area. Clicking
- // on the "Copy" buttons above each of the source pictures
- // causes the picture to be copied to the destination area.
- // Picture 1 is labelled as "flickery animation" and picture 2
- // is labelled as "smooth animation." When you put the cursor
- // over each picture, you should see a difference in how a
- // colored circle is animated over the picture. You should
- // occasionally see the background "flicker" through on
- // picture 1, but not on picture 2 because it uses an
- // intermediary GWorld to draw in.
- //
- // The Fade to black button over the destination area will
- // cause that area to fade to black from whatever happens to
- // be in there. It does this by repeatedly copying a gray
- // rectangle from a GWorld into the destination area using
- // the subPin transfer mode of CopyBits. The erase button
- // erases the destination area.
- //
- // The Fade picture buttons cause the picture under the
- // button to be faded into whatever is currently in the
- // destination area. This is accomplished using CopyBits'
- // blend transfer mode.
- //
- // Questions? Comments? Praise? Criticism? Jobs? Send them
- // all to me at KNEworley@aol.com. I'm a 'freelance'
- // programmer. I work on applications as well as low-level
- // software (control panels, INITs, etc.)
- //
-
- #include <QDOffscreen.h>
-
- // ===================== DEFINES =====================
-
- #define kMainDlgID 128
-
- #define kPict1ID 128
- #define kPict2ID 129
-
- #define kMainDlgQuit 1
- #define kMainDlgCopyOne 2
- #define kMainDlgFadeOne 3
- #define kMainDlgCopyTwo 4
- #define kMainDlgFadeTwo 5
- #define kMainDlgErase 6
- #define kMainDlgFadeToBlack 7
- #define kMainDlgPICTOne 8
- #define kMainDlgPICTTwo 9
- #define kMainDlgDestPICT 10
- #define kMainDlgFadeSpeed 15
-
- #define kSys7DlgID 129
- #define kMemoryOutDlgID 130
- #define kGWorldErrDlgID 131
- #define kNotYetImplDlgID 132
-
- #define kAlertOKButton 1
-
- // ===================== MACROS =====================
-
- // w can be a WindowPtr, a DialogPtr, or a GWorldPtr. In any of these
- // cases, it returns the correct "bitmap" to send to CopyBits in the
- // source or destination bitmap parameter.
- #define WINBITMAP(w) ((((WindowPeek)(w))->port).portBits)
-
- // w can also be a WindowPtr, DialogPtr, or GWorldPtr for any of these.
- #define WINPORTRECT(w) ((((WindowPeek)(w))->port).portRect)
- #define WINDOWWIDTH(w) (WINPORTRECT(w).right - WINPORTRECT(w).left)
- #define WINDOWHEIGHT(w) (WINPORTRECT(w).bottom - WINPORTRECT(w).top)
- #define WINCONTENTRECT(w) ((**((WindowPeek)(w))->contRgn).rgnBBox)
- #define WINCONTENTRGN(w) (((WindowPeek)(w))->contRgn)
- #define WINVISIBLERGN(w) (((WindowPeek)(w))->port.visRgn)
- #define WINSTRUCTRECT(w) ((**((WindowPeek)(w))->strucRgn).rgnBBox)
- #define WINSTRUCTRGN(w) (((WindowPeek)(w))->strucRgn)
- #define WINUPDATERECT(w) ((**((WindowPeek)(w))->updateRgn).rgnBBox)
- #define WINUPDATERGN(w) (((WindowPeek)(w))->updateRgn)
-
- // This takes a GDHandle (device handle)
- #define PIXELDEPTH(x) ((**((**(x)).gdPMap)).pixelSize)
-
- // r is a Rect
- #define TOPLEFT(r) (* (Point*) &(r.top) )
- #define BOTRIGHT(r) (* (Point*) &(r.bottom) )
-
- // ===================== PROTOTYPES =====================
-
- void main( void );
- void InitToolbox( void );
-
- short GetSysVersion( void );
- Boolean HasColorQuickDraw( void );
-
- Handle GetItemHandle( DialogPtr dlg, short itemNo );
- void GetItemRect( DialogPtr dlg, short itemNo, Rect *aRect );
- long GetDialogNumberField( DialogPtr dlg, short itemNo );
-
- void DoAlert( short dlgID, Boolean playAlert );
-
- GDHandle WindowDevice( WindowPtr winPtr );
-
- void FadeToBlack( WindowPtr destWin, Rect *destRect, short fadeSpeed );
-
- void FadeToImage( GWorldPtr srcImage, Rect *srcRect,
- WindowPtr destWin, Rect *destRect, short fadeSpeed );
-
- void FlickerAnimate( GWorldPtr srcPict, Rect *destRect );
- void SmoothAnimate( GWorldPtr srcPict, Rect *destRect );
-
- // ===================== FUNCTIONS =====================
-
- void main( void )
- {
- DialogPtr mainDlg;
- DialogPtr aDlg;
- Rect pict1Rect;
- Rect pict2Rect;
- Rect destRect;
- PenState savedPen;
- short itemHit;
- RGBColor savedFore;
- RGBColor savedBack;
- RGBColor blackColor;
- RGBColor whiteColor;
- short fadeSpeed;
- OSErr myErr;
- Rect pict1GRect;
- Rect pict2GRect;
- GWorldPtr pict1GWorld;
- GWorldPtr pict2GWorld;
- EventRecord myEvent;
-
- // Make colors for use later.
-
- blackColor.red = blackColor.green = blackColor.blue = 0;
- whiteColor.red = whiteColor.green = whiteColor.blue = 0xFFFF;
-
- // Initialize the Mac Toolbox
-
- InitToolbox();
-
- // Check the system version. This project requires System 7
- // or later for the GWorlds.
-
- if ( GetSysVersion() < 7 )
- {
- DoAlert( kSys7DlgID, true );
- ExitToShell();
- }
-
- // Load the main (only) dialog and display it on screen. This
- // automatically displays our two source PICTS. Since there is
- // a 'dctb' (Dialog Color Table) resource with the same ID
- // as the dialog, the Dialog Manager uses NewColorDialog to
- // make the dialog, thus giving us a color drawing port.
-
- mainDlg = GetNewDialog( kMainDlgID, NULL, (WindowPtr)(-1L) );
- if ( !mainDlg )
- {
- DoAlert( kMemoryOutDlgID, true );
- ExitToShell();
- }
-
- // Select the text in the fade speed text edit box.
-
- SelectDialogItemText( mainDlg, kMainDlgFadeSpeed, 0, 255 );
-
- // Make sure the dialog is visible.
-
- ShowWindow( mainDlg );
- SetGWorld( (CGrafPtr)mainDlg, NULL );
- PenNormal();
-
- // Get the picture rectangles and the destination picture's
- // rectangle. Save them for later use.
-
- GetItemRect( mainDlg, kMainDlgPICTOne, &pict1Rect );
- GetItemRect( mainDlg, kMainDlgPICTTwo, &pict2Rect );
- GetItemRect( mainDlg, kMainDlgDestPICT, &destRect );
-
- // Draw a box around each of the picture areas.
-
- {
- Rect tempRect;
-
- tempRect = destRect;
- InsetRect( &tempRect, -1, -1 );
- FrameRect( &tempRect );
- tempRect = pict1Rect;
- InsetRect( &tempRect, -1, -1 );
- FrameRect( &tempRect );
- tempRect = pict2Rect;
- InsetRect( &tempRect, -1, -1 );
- FrameRect( &tempRect );
- }
-
- // Draw each of the two "source" pictures into an offscreen
- // Graphics World for use later. For example, when the user
- // passes the cursor over the left picture, regular animation
- // techniques are used to make a circle "float" above the
- // picture (causes flicker). This involves repeatedly
- // copying the original picture to the window, then drawing
- // the circle over it. When the user passes the cursor over
- // the right picture, the original picture is drawn to an
- // offscreen gworld and the circle is drawn over it, then
- // that image is drawn to the window resulting in flicker-free
- // animation of the floating circle.
- //
- // We need the two gworlds here so we have the original
- // pictures to copy from.
-
- // Convert the destination rectangles into global coordinates
-
- pict1GRect = pict1Rect;
- LocalToGlobal( &TOPLEFT(pict1GRect) );
- LocalToGlobal( &BOTRIGHT(pict1GRect) );
-
- pict2GRect = pict2Rect;
- LocalToGlobal( &TOPLEFT(pict2GRect) );
- LocalToGlobal( &BOTRIGHT(pict2GRect) );
-
- // Create offscreen GWorlds with the same size and depth as the
- // destination rectangles. The parameters are as follows:
- // &pictxGWorld ptr to new graphics world
- // 0 bit depth same as graphics device of dest rect
- // &pictxGRect bounds rectangle of GWorld
- // NULL handle to a color table record - NULL means
- // use the default record for that depth
- // NULL handle to a graphics device record - we aren't
- // creating a new graphics device
- // 0L no flags
-
- myErr = NewGWorld( &pict1GWorld, 0, &pict1GRect, NULL, NULL, 0L );
- myErr = NewGWorld( &pict2GWorld, 0, &pict2GRect, NULL, NULL, 0L );
-
- // I'm just assuming here that an error means we don't have enough memory.
-
- if ( myErr || !pict1GWorld || !pict2GWorld )
- {
- DoAlert( kMemoryOutDlgID, true );
- ExitToShell();
- }
-
- // Draw the pictures in the picture offscreen graphics worlds.
- // When I read in the PICT resources, I'm just assuming there won't
- // be any errors because they're already loaded by the dialog
- // anyway, but you never know. You probably really should check :)
- // See the FadeToBlack routine for more explanation on locking and
- // unlocking pixels.
- {
- PicHandle aPict;
- PixMapHandle thePixMap;
-
- // get and draw picture 1
-
- thePixMap = GetGWorldPixMap( pict1GWorld );
- LockPixels( thePixMap );
- SetGWorld( (CGrafPtr)pict1GWorld, NULL );
- aPict = GetPicture( kPict1ID );
- DrawPicture( aPict, &WINPORTRECT( pict1GWorld ) );
- UnlockPixels( thePixMap );
-
- // get and draw picture 2
-
- thePixMap = GetGWorldPixMap( pict2GWorld );
- LockPixels( thePixMap );
- SetGWorld( (CGrafPtr)pict2GWorld, NULL );
- aPict = GetPicture( kPict2ID );
- DrawPicture( aPict, &WINPORTRECT( pict2GWorld ) );
- UnlockPixels( thePixMap );
-
- // make sure and restore the dialog as the current port
-
- SetGWorld( (CGrafPtr)mainDlg, NULL );
- }
-
- // Now wait for the user to press a button in the dialog
-
- itemHit = -1;
- while ( itemHit != kMainDlgQuit )
- {
- WaitNextEvent( everyEvent, &myEvent, GetCaretTime(), NULL );
-
- // Check for disk events (bad disk mount).
-
- if ( (myEvent.what == diskEvt) &&
- (HiWord(myEvent.message) != noErr) )
- {
- Point dlgUpLeftCorner = { 100, 80 }; // ignored in Sys 7
-
- DIBadMount( dlgUpLeftCorner, myEvent.message ); // ignore result
- }
- // If we get an update event, redraw the squares around the
- // picture areas.
- else if ( myEvent.what == updateEvt )
- {
- Rect tempRect;
-
- tempRect = destRect;
- InsetRect( &tempRect, -1, -1 );
- FrameRect( &tempRect );
- tempRect = pict1Rect;
- InsetRect( &tempRect, -1, -1 );
- FrameRect( &tempRect );
- tempRect = pict2Rect;
- InsetRect( &tempRect, -1, -1 );
- FrameRect( &tempRect );
- }
-
- // If the mouse is over one of the pictures, call a routine
- // to animate a "floating circle" over the picture. A
- // different method is used for each picture.
- {
- Point mouseLoc;
-
- GetMouse( &mouseLoc );
-
- if ( PtInRect( mouseLoc, &pict1Rect ) )
- FlickerAnimate( pict1GWorld, &pict1Rect );
- else if ( PtInRect( mouseLoc, &pict2Rect ) )
- SmoothAnimate( pict2GWorld, &pict2Rect );
- }
-
- // Pass the event to DialogSelect which takes care of tracking
- // controls and updating everything (except the destination
- // area) for us.
-
- if ( DialogSelect( &myEvent, &aDlg, &itemHit ) )
- {
- // What we do here depends on what the user clicked
-
- switch( itemHit )
- {
- case kMainDlgCopyOne:
-
- // Save the pen state and foreground/background colors
-
- GetPenState( &savedPen );
- GetForeColor( &savedFore );
- GetBackColor( &savedBack );
-
- // Set foreground color to black, background color to white
-
- RGBForeColor( &blackColor );
- RGBBackColor( &whiteColor );
-
- // Just use CopyBits to copy the PICT. We're actually
- // copying from one place on the dialog to another here.
-
- CopyBits( &WINBITMAP( mainDlg ), &WINBITMAP( mainDlg ),
- &pict1Rect, &destRect, srcCopy, NULL );
-
- // Restore the saved pen state and colors
-
- SetPenState( &savedPen );
- RGBForeColor( &savedFore );
- RGBBackColor( &savedBack );
-
- break;
-
- case kMainDlgFadeOne:
-
- // Select the fade speed.
-
- SelectDialogItemText( mainDlg, kMainDlgFadeSpeed, 0, 255 );
-
- // Get the fade speed from the dialog.
-
- fadeSpeed = GetDialogNumberField( mainDlg,
- kMainDlgFadeSpeed );
-
- // Call FadeToImage to fade picture 1 into the
- // destination area.
-
- FadeToImage( pict1GWorld, &WINPORTRECT( pict1GWorld ),
- mainDlg, &destRect, fadeSpeed );
-
- break;
-
- case kMainDlgCopyTwo:
-
- // Save the pen state and foreground/background colors
-
- GetPenState( &savedPen );
- GetForeColor( &savedFore );
- GetBackColor( &savedBack );
-
- // Set foreground color to black, background color to white
-
- RGBForeColor( &blackColor );
- RGBBackColor( &whiteColor );
-
- // Just use CopyBits to copy the PICT from one place in
- // the window to another.
-
- CopyBits( &WINBITMAP( mainDlg ), &WINBITMAP( mainDlg ),
- &pict2Rect, &destRect, srcCopy, NULL );
-
- // Restore the saved pen state and colors
-
- SetPenState( &savedPen );
- RGBForeColor( &savedFore );
- RGBBackColor( &savedBack );
-
- break;
-
- case kMainDlgFadeTwo:
-
- // Select the fade speed.
-
- SelectDialogItemText( mainDlg, kMainDlgFadeSpeed, 0, 255 );
-
- // Get the fade speed from the dialog.
-
- fadeSpeed = GetDialogNumberField( mainDlg,
- kMainDlgFadeSpeed );
-
- // Call FadeToImage to fade picture 2 into the
- // destination area.
-
- FadeToImage( pict2GWorld, &WINPORTRECT( pict2GWorld ),
- mainDlg, &destRect, fadeSpeed );
-
- break;
-
- case kMainDlgErase:
-
- // Erase the destination area.
-
- EraseRect( &destRect );
-
- break;
-
- case kMainDlgFadeToBlack:
-
- // Select the fade speed.
-
- SelectDialogItemText( mainDlg, kMainDlgFadeSpeed, 0, 255 );
-
- // Get the fade speed from the dialog.
-
- fadeSpeed = GetDialogNumberField( mainDlg,
- kMainDlgFadeSpeed );
-
- // And call FadeToBlack to fade the destination rectangle.
-
- FadeToBlack( mainDlg, &destRect, fadeSpeed );
-
- break;
-
- case kMainDlgQuit:
-
- break;
- }
- }
- }
- }
-
- void InitToolbox( void )
- {
- /* Initialize the Mac Toolbox Managers */
-
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- FlushEvents(everyEvent,0);
- TEInit();
- InitDialogs(0L);
- InitCursor();
- }
-
- // GetSysVersion returns 7 if the system version is 7 or later,
- // 6 if it's 6 or later (but not 7), and 0 if earlier than 6.
- //
- short GetSysVersion( void )
- {
- SysEnvRec env;
-
- SysEnvirons( 2, &env );
-
- if ( env.systemVersion >= 0x0700 )
- return 7;
- else if ( env.systemVersion >= 0x0600 )
- return 6;
- else
- return 0;
- }
-
- // HasColorQuickDraw returns true if the Mac has color
- // QuickDraw.
- //
- Boolean HasColorQuickDraw( void )
- {
- SysEnvRec env;
-
- SysEnvirons( 2, &env );
-
- return env.hasColorQD;
- }
-
- // GetItemHandle returns a handle to a dialog item given the
- // dialog ptr and the item number.
- //
- Handle GetItemHandle( DialogPtr dlg, short itemNo )
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
-
- GetDialogItem( dlg, itemNo, &itemType, &itemHandle, &itemRect );
-
- return itemHandle;
- }
-
- // GetItemRect returns the rectangle of a dialog item (in local
- // coordinates) given the dialog ptr, and the item number.
- //
- void GetItemRect( DialogPtr dlg, short itemNo, Rect *aRect )
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
-
- GetDialogItem( dlg, itemNo, &itemType, &itemHandle, &itemRect );
-
- (*aRect) = itemRect;
- }
-
- // GetDialogNumberField gets the text in the field specified by itemNo
- // in the dialog specified by dlg and converts it into a number. The
- // number is returned as the function result.
- //
- long GetDialogNumberField( DialogPtr dlg, short itemNo )
- {
- Str255 theStr;
- long theNum;
-
- GetDialogItemText( GetItemHandle( dlg, itemNo ), theStr );
- StringToNum( theStr, &theNum );
- return theNum;
- }
-
-
- void DoAlert( short dialogID, Boolean playAlert )
- {
- /* This routine displays an alert whose resource ID number is specified
- * in the parameter dialogID. The dialog specified is expected to have
- * at least one button (usually labeled "OK") which will be the default
- * button and have an ID if 1. When the user presses this button, the
- * alert will be dismissed.
- */
-
- WindowPtr currentPort; /* store the current port here */
- DialogPtr theDlg; /* to store our dialog in */
-
- short itemType; /* these 3 local variables are used to */
- Handle itemHandle; /* manipulate items in the dialog. */
- Rect itemRect;
-
- short itemHit; /* use with ModalDialog */
-
- // Save the current grafPort
-
- GetPort( ¤tPort );
-
- // Now, load our dialog resource and display it.
-
- // load the dialog resource
-
- theDlg = GetNewDialog( dialogID, NULL, (WindowPtr)-1L );
-
- // make the dialog the current port
-
- SetPort( theDlg );
-
- // if the parameter specifies, do a system beep
-
- if ( playAlert )
- SysBeep( 3 );
-
- // now make sure the dialog is visible
-
- ShowWindow( theDlg );
-
- /* Get the OK button item and draw a bold border around it to show that
- * it's the default button.
- */
-
- GetDItem( theDlg, kAlertOKButton, &itemType, &itemHandle, &itemRect );
- InsetRect( &itemRect, -4, -4 );
- PenSize( 3, 3 );
- FrameRoundRect( &itemRect, 16, 16 );
- PenSize( 1, 1 );
-
- // Loop and call ModalDialog until the user presses the OK button
- // This routine requires that whatever alert is shown, the button with
- // id number kAlertOKButton is the one that should dismiss the dialog.
-
- ModalDialog( NULL, &itemHit );
- while ( itemHit != kAlertOKButton )
- ModalDialog( NULL, &itemHit );
-
- /* Now get rid of the dialog and set the port back to the control panel */
-
- DisposDialog( theDlg );
- SetPort( currentPort );
- }
-
- // WindowDevice returns a handle to the graphics device record of
- // the monitor that the window specified is displayed on.
- //
- GDHandle WindowDevice( WindowPtr winPtr )
- {
- GDHandle theDevice;
- Point targetPt;
-
- targetPt = TOPLEFT( ((WindowPeek)winPtr)->port.portRect );
-
- theDevice = GetDeviceList();
- while ( !PtInRect( targetPt, &((**theDevice).gdRect) ) )
- {
- theDevice = GetNextDevice( theDevice );
- if ( theDevice == NULL )
- {
- theDevice = GetMainDevice();
- break;
- }
- }
-
- return theDevice;
- }
-
- // FadeToBlack uses CopyBits and an offscreen graphics world to
- // fade an area (specified by destRect) in a window (specified
- // by destWin) to black. It does this by creating an offscreen
- // graphics world, painting the GWorld gray, then repeatedly
- // copying the gray rectangle to the destination area using the
- // subPin transfer method of CopyBits. This causes the destination
- // to grow darker and darker.
- //
- void FadeToBlack( WindowPtr destWin, Rect *destRect, short fadeSpeed )
- {
- CGrafPtr savedPort;
- GDHandle savedDevice;
- GWorldPtr offscreenWorld;
- Rect offscreenRect;
- OSErr myErr;
- PenState savedPen;
- RGBColor savedFore;
- RGBColor savedBack;
- PixMapHandle thePixMap;
- long repetitions;
- RGBColor grayColor;
- RGBColor blackColor;
- RGBColor whiteColor;
-
- // Make the black and white colors
-
- blackColor.blue = blackColor.green = blackColor.red = 0;
- whiteColor.blue = whiteColor.green = whiteColor.red = 0xFFFF;
-
- // Save the current port/device. This should be used instead
- // of GetPort. Though savedPort is defined as a CGrafPtr,
- // the routine may return a GrafPtr or pointer to a GWorld
- // instead (GWorldPtr).
-
- GetGWorld( &savedPort, &savedDevice );
-
- // Set the current port to the destination window
-
- SetGWorld( (CGrafPtr)destWin, NULL );
-
- // Save the pen state and color info of the destination window
-
- GetPenState( &savedPen );
- GetForeColor( &savedFore );
- GetBackColor( &savedBack );
-
- // Make sure the foreground color of the destination window
- // is black and the background color is white.
-
- RGBForeColor( &blackColor );
- RGBBackColor( &whiteColor );
-
- // Convert the destination rectangle into global coordinates
-
- offscreenRect = (*destRect);
- LocalToGlobal( &TOPLEFT(offscreenRect) );
- LocalToGlobal( &BOTRIGHT(offscreenRect) );
-
- // Make the offscreen rectangle smaller. It doesn't matter since it's
- // all the same color and it'll use up less memory.
-
- offscreenRect.right = offscreenRect.left + 2;
- offscreenRect.bottom = offscreenRect.top + 2;
-
- // Create an offscreen GWorld with the same depth as the
- // destination window/rectangle. The parameters are as follows:
- // &offscreenWorld ptr to new graphics world
- // 0 bit depth same as graphics device of dest rect
- // &offscreenRect bounds rectangle of my GWorld
- // NULL handle to a color table record - NULL means
- // use the default record for that depth
- // NULL handle to a graphics device record - we aren't
- // creating a new graphics device
- // 0L no flags
-
- myErr = NewGWorld( &offscreenWorld, 0, &offscreenRect, NULL, NULL, 0L );
-
- // Make sure the GWorld was created
-
- if ( myErr )
- {
- DoAlert( kGWorldErrDlgID, true );
- ExitToShell();
- }
-
- // Make the GWorld the current port
-
- SetGWorld( offscreenWorld, NULL );
-
- // Get the GWorld's pixel map handle and lock the pixels while we're
- // drawing in the GWorld. We have to do this because a GWorld actually
- // holds its pixel map in a handle rather than a pointer. LockPixels
- // makes sure the pixel map doesn't move. You should lock a GWorld's
- // pixels before drawing to or copying from the GWorld (and unlock
- // them afterward).
-
- thePixMap = GetGWorldPixMap( offscreenWorld );
- LockPixels( thePixMap );
-
- // The speed of the fade determines what shade of gray we'll paint
- // the offscreen GWorld. fadeSpeed can range from 0 to 20 with 20
- // being the fastest.
- {
- unsigned short maxValue=0xFFFF;
-
- if ( fadeSpeed <= 0 ) fadeSpeed = 1; // make sure speed is not zero
- if ( fadeSpeed > 20 ) fadeSpeed = 20; // make sure not over 20
-
- grayColor.blue = (fadeSpeed * 625) + 8000;
- grayColor.red = grayColor.green = grayColor.blue;
- RGBForeColor( &grayColor );
- repetitions = maxValue / grayColor.blue;
- }
-
- // Paint it all gray
-
- PaintRect( &(offscreenWorld->portRect) );
-
- // Make the destination window the current port
-
- SetGWorld( (CGrafPtr)destWin, NULL );
-
- // Loop and use CopyBits to copy the gray rectangle into the
- // destination window/rect using the subPin transfer method
- // so that the picture gets darker and darker.
-
- while ( repetitions )
- {
- CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
- &(offscreenWorld->portRect), destRect, subPin, NULL );
-
- repetitions--;
- }
-
- // Make the GWorld the current port
-
- SetGWorld( offscreenWorld, NULL );
-
- // Now we'll do a fast fade just to make sure everything went completely
- // to black.
- {
- unsigned short maxValue=0xFFFF;
-
- grayColor.blue = 20500;
- grayColor.red = grayColor.green = grayColor.blue;
- RGBForeColor( &grayColor );
- repetitions = maxValue / grayColor.blue + 1;
- }
-
- // Paint it all gray
-
- PaintRect( &(offscreenWorld->portRect) );
-
- // Make the destination window the current port
-
- SetGWorld( (CGrafPtr)destWin, NULL );
-
- // Loop and use CopyBits to copy the gray rectangle into the
- // destination window/rect using the subPin transfer method
- // so that the picture gets darker and darker.
-
- while ( repetitions )
- {
- CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
- &(offscreenWorld->portRect), destRect, subPin, NULL );
-
- repetitions--;
- }
-
- // Unlock the pixels again.
-
- UnlockPixels( thePixMap );
-
- // Restore the saved port/device
-
- SetGWorld( savedPort, savedDevice );
-
- // Restore the pen state and color info of the destination window
-
- SetPenState( &savedPen );
- RGBForeColor( &savedFore );
- RGBBackColor( &savedBack );
-
- // Dispose of the GWorld
-
- DisposeGWorld( offscreenWorld );
- }
-
-
- // FadeToImage takes the source image and does a smooth fade in
- // the destination window and rect from the image that is currently
- // there to the source image. This is done using CopyBits with
- // the "blend" transfer mode.
- //
- void FadeToImage( GWorldPtr srcImage, Rect *srcRect,
- WindowPtr destWin, Rect *destRect, short fadeSpeed )
- {
- CGrafPtr savedPort;
- GDHandle savedDevice;
- RGBColor savedFore, savedBack;
- PenState savedPen;
- RGBColor grayColor;
- RGBColor blackColor;
- RGBColor whiteColor;
- float speed;
- unsigned short lastColor;
-
- // Make sure speed is within our limits and set it appropriately.
- // We want to end up with a range of 1.2 to 3.2 from the original
- // 0 to 20 range.
-
- if ( fadeSpeed < 1 ) speed = 1.2;
- else if ( fadeSpeed > 20 ) speed = 3.2;
- else speed = 1.2 + (fadeSpeed/10);
-
- // Make the black and white colors
-
- blackColor.blue = blackColor.green = blackColor.red = 0;
- whiteColor.blue = whiteColor.green = whiteColor.red = 0xFFFF;
-
- // Save the current port and device
-
- GetGWorld( &savedPort, &savedDevice );
-
- // Set the port to the destination window and save its
- // pen state and fore/background color values.
-
- SetGWorld( (CGrafPtr)destWin, NULL );
- GetPenState( &savedPen );
- GetForeColor( &savedFore );
- GetBackColor( &savedBack );
-
- // Make sure the port's fore and background colors are set
- // correctly for CopyBits to work correctly.
-
- RGBForeColor( &blackColor );
- RGBBackColor( &whiteColor );
-
- // Lock the pixels in the source image. This is required
- // when copying from a GWorld.
-
- LockPixels( GetGWorldPixMap( srcImage ) );
-
- // Set the beginning blend weight. This will be multiplied by
- // speed before being used the first time.
-
- grayColor.blue = grayColor.green = grayColor.red = 0x0600;
- lastColor = 0;
-
- // Loop and copy the source image to the destination
- // blending more and more of the source image in by using
- // a lighter and lighter "blend weight" (set by the OpColor
- // function).
-
- while ( grayColor.blue < 0xFFFF )
- {
- // Lighten the blend weight color.
-
- grayColor.blue *= speed;
-
- // Make sure the number didn't roll over.
-
- if ( grayColor.blue < lastColor )
- grayColor.blue = 0xFFFF;
-
- grayColor.red = grayColor.green = grayColor.blue;
-
- // Remember the number for next time.
-
- lastColor = grayColor.blue;
-
- // Set the new blend weight.
-
- OpColor( &grayColor );
-
- // copy the image
-
- CopyBits( &WINBITMAP( srcImage ),
- &WINBITMAP( destWin ),
- srcRect, destRect, blend, NULL );
- }
-
- // Finally, just copy the source image to the destination
- // window unchanged to make sure the transformation is
- // complete.
-
- CopyBits( &WINBITMAP( srcImage ),
- &WINBITMAP( destWin ),
- srcRect, destRect, srcCopy, NULL );
-
- // Reset the blend weight to black.
- // This is the "normal" weight.
-
- OpColor( &blackColor );
-
- // Unlock the pixels in the source image.
-
- UnlockPixels( GetGWorldPixMap( srcImage ) );
-
- // Restore the destination window's properties.
-
- SetPenState( &savedPen );
- RGBForeColor( &savedFore );
- RGBBackColor( &savedBack );
-
- // Restore the current port and device.
-
- SetGWorld( savedPort, savedDevice );
- }
-
- // FlickerAnimate animates a colored circle floating over
- // a picture at the mouse location. It draws directly to
- // the screen resulting in a circle that the background
- // occasionally "flickers" through. Drawing will occur in
- // the current port.
- //
- void FlickerAnimate( GWorldPtr srcPict, Rect *destRect )
- {
- Point mouseLoc;
- Rect mouseRect;
- RGBColor savedFore, savedBack;
- RGBColor blackColor, whiteColor;
- PixMapHandle thePixMap;
- RgnHandle savedClip;
- RGBColor redColor;
- long ignore;
-
- // Make black and white colors.
-
- blackColor.blue = blackColor.green = blackColor.red = 0;
- whiteColor.blue = whiteColor.green = whiteColor.red = 0xFFFF;
-
- // Make the color to draw the circle with.
-
- redColor.blue = redColor.green = 0;
- redColor.red = 0xFFFF;
-
- // Save fore and background colors and make them
- // fore-black and back-white.
-
- GetForeColor( &savedFore ); GetBackColor( &savedBack );
- RGBForeColor( &blackColor ); RGBBackColor( &whiteColor );
-
- // Save the clipping region.
-
- savedClip = NewRgn();
- GetClip( savedClip );
-
- // Set the clipping region to just cover the picture.
-
- ClipRect( destRect );
-
- // Lock the pixel map of the src GWorld while copying from it.
-
- thePixMap = GetGWorldPixMap( srcPict );
- LockPixels( thePixMap );
-
- // Loop and draw the picture and circle repeatedly.
-
- do
- {
- // Get a mouse location.
-
- GetMouse( &mouseLoc );
-
- // Make a square around the mouse location to draw
- // the circle in.
-
- mouseRect.left = mouseRect.right = mouseLoc.h;
- mouseRect.top = mouseRect.bottom = mouseLoc.v;
- InsetRect( &mouseRect, -20, -20 );
-
- // Copy the picture to the window.
-
- CopyBits( &WINBITMAP( srcPict ),
- &WINBITMAP( FrontWindow() ),
- &WINPORTRECT( srcPict ),
- destRect, srcCopy, NULL );
-
- // Draw the circle at the mouse location.
-
- RGBForeColor( &redColor );
- PaintOval( &mouseRect );
- RGBForeColor( &blackColor );
-
- // Delay for a fraction of a second here. If we
- // don't, the flickering is really, really bad.
-
- Delay( 2, &ignore );
-
- } while ( PtInRect( mouseLoc, destRect ) );
-
- // Draw the picture one more time to make sure the
- // circle is erased.
-
- CopyBits( &WINBITMAP( srcPict ),
- &WINBITMAP( FrontWindow() ),
- &WINPORTRECT( srcPict ),
- destRect, srcCopy, NULL );
-
- // Unlock the GWorld's pixel map.
-
- UnlockPixels( thePixMap );
-
- // Restore the clipping region.
-
- SetClip( savedClip );
-
- // Restore the saved fore and background colors.
-
- RGBForeColor( &savedFore );
- RGBBackColor( &savedBack );
- }
-
- // SmoothAnimate animates a colored circle floating over
- // a picture at the mouse location. It draws to a GWorld
- // then copies the GWorld to the screen. This results in
- // flicker-free animation where the background never
- // shows through the floating circle.
- //
- void SmoothAnimate( GWorldPtr srcPict, Rect *destRect )
- {
- Point mouseLoc;
- Rect mouseRect;
- RGBColor savedFore, savedBack;
- RGBColor blackColor, whiteColor;
- PixMapHandle srcPixMap, midPixMap;
- GWorldPtr middleMan;
- CGrafPtr thisWindow;
- GDHandle thisDevice;
- RGBColor purpleColor;
- OSErr myErr;
-
- // Save the current window and device (this is the window
- // we're drawing into.)
-
- GetGWorld( &thisWindow, &thisDevice );
-
- // Make black and white colors.
-
- blackColor.blue = blackColor.green = blackColor.red = 0;
- whiteColor.blue = whiteColor.green = whiteColor.red = 0xFFFF;
-
- // Make the color to draw the circle with.
-
- purpleColor.blue = purpleColor.red = 0xFFFF;
- purpleColor.green = 0;
-
- // Save fore and background colors and make them
- // fore-black and back-white.
-
- GetForeColor( &savedFore ); GetBackColor( &savedBack );
- RGBForeColor( &blackColor ); RGBBackColor( &whiteColor );
-
- // Make a GWorld to draw the picture and circle into. The
- // onscreen image will be copied from this "middle man."
- // It is the same size and depth as the destination
- // on screen.
- // &middleMan ptr to new graphics world
- // 0 bit depth same as graphics device of dest rect
- // destRect bounds rectangle of new GWorld
- // NULL handle to a color table record - NULL means
- // use the default record for that depth
- // NULL handle to a graphics device record - we aren't
- // creating a new graphics device
- // 0L no flags
-
- myErr = NewGWorld( &middleMan, 0, destRect, NULL, NULL, 0L );
-
- // Make sure the GWorld was created
-
- if ( myErr || !middleMan )
- {
- DoAlert( kGWorldErrDlgID, true );
- ExitToShell();
- }
-
- // Lock the pixel map of the src GWorld and the middleMan
- // GWorld while copying from them.
-
- srcPixMap = GetGWorldPixMap( srcPict );
- LockPixels( srcPixMap );
- midPixMap = GetGWorldPixMap( middleMan );
- LockPixels( midPixMap );
-
- // Loop and draw the pict and the circle repeatedly.
-
- do
- {
- // Get a mouse location and translate into coordinates
- // local to the middleMan GWorld.
-
- GetMouse( &mouseLoc );
- mouseLoc.h -= destRect->left;
- mouseLoc.v -= destRect->top;
-
- // Make a square around the mouse location to draw
- // the circle in.
-
- mouseRect.left = mouseRect.right = mouseLoc.h;
- mouseRect.top = mouseRect.bottom = mouseLoc.v;
- InsetRect( &mouseRect, -20, -20 );
-
- // Set the current port to middleMan.
-
- SetGWorld( (CGrafPtr)middleMan, NULL );
-
- // Copy the picture to the middleMan GWorld.
-
- CopyBits( &WINBITMAP( srcPict ),
- &WINBITMAP( middleMan ),
- &WINPORTRECT( srcPict ),
- &WINPORTRECT( middleMan ), srcCopy, NULL );
-
- // Draw the circle at the mouse location.
-
- RGBForeColor( &purpleColor );
- PaintOval( &mouseRect );
- RGBForeColor( &blackColor );
-
- // Reset the current port to the destination window.
-
- SetGWorld( thisWindow, thisDevice );
-
- // Now copy the middleMan image to the destination
- // window on screen.
-
- CopyBits( &WINBITMAP( middleMan ),
- &WINBITMAP( thisWindow ),
- &WINPORTRECT( middleMan ),
- destRect, srcCopy, NULL );
-
- } while ( PtInRect( mouseLoc, &WINPORTRECT( middleMan ) ) );
-
- // Draw the picture one more time to make sure the
- // circle is erased.
-
- CopyBits( &WINBITMAP( srcPict ),
- &WINBITMAP( FrontWindow() ),
- &WINPORTRECT( srcPict ),
- destRect, srcCopy, NULL );
-
- // Unlock the GWorld's and middleMan's pixel maps.
-
- UnlockPixels( srcPixMap );
- UnlockPixels( midPixMap );
-
- // Dispose of the middleMan GWorld.
-
- DisposeGWorld( middleMan );
-
- // Restore the saved fore and background colors.
-
- RGBForeColor( &savedFore );
- RGBBackColor( &savedBack );
- }
-
-